package com.gary.spring.proxy;

import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Method;

/**
 * @author peng_rui
 * @date 2022/7/5
 */
public class SpringProxyDemo2 {
    public static void main(String[] args) throws Exception {

//        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
//        pointcut.setExpression("execution(* bar())");
//        //判断表达式是否匹配的方法
//        System.out.println(pointcut.matches(T1.class.getMethod("foo"), T1.class));
//        System.out.println(pointcut.matches(T1.class.getMethod("bar"), T1.class));
//
//        AspectJExpressionPointcut pointcut2 = new AspectJExpressionPointcut();
//        pointcut2.setExpression("@annotation(org.springframework.web.bind.annotation.GetMapping)");
//        System.out.println(pointcut2.matches(T1.class.getMethod("foo"), T1.class));
//        System.out.println(pointcut2.matches(T1.class.getMethod("bar"), T1.class));

        //spring 中事务控制的@Transactional 使用的切入方式
        StaticMethodMatcherPointcut pointcut = new StaticMethodMatcherPointcut() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                //从指定的 AnnotatedElement 中获取注解信息 AnnotatedElement 可以是 方法 类
                MergedAnnotations annotations = MergedAnnotations.from(method);
                if (annotations.isPresent(Transactional.class)) {
                    return true;
                }

                //, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY 表示读取本类加所实现的接口
                MergedAnnotations annotations1 = MergedAnnotations.from(targetClass);
                if (annotations1.isPresent(Transactional.class)) {
                    return true;
                }
                return false;
            }
        };
        System.out.println(pointcut.matches(T1.class.getMethod("foo"), T1.class));
        System.out.println(pointcut.matches(T1.class.getMethod("bar"), T1.class));

        System.out.println(pointcut.matches(T2.class.getMethod("foo"), T2.class));
        System.out.println(pointcut.matches(T3.class.getMethod("foo"), T3.class));
    }

    static class T1 {
        @Transactional(rollbackFor = Exception.class)
        public void foo() {

        }

        public void bar() {

        }
    }

    @Transactional(rollbackFor = Exception.class)
    static class T2 {
        public void foo() {

        }
    }

    @Transactional(rollbackFor = Exception.class)
    interface I3 {
        void foo();
    }

    static class T3 implements I3 {

        @Override
        public void foo() {

        }
    }
}
